﻿Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Drawing
Imports System.Runtime.InteropServices

Namespace System.Workflow.ComponentModel.Design
    Friend Class ActivityDesignerConnectorRouter
        ' Methods
        Private Shared Function AreAllSegmentsVerticalOrHorizontal(ByVal segments As Point()) As Boolean
            If ((segments Is Nothing) OrElse (segments.Length = 0)) Then
                Return False
            End If
            Dim i As Integer
            For i = 1 To segments.Length - 1
                If ((segments((i - 1)).X <> segments(i).X) AndAlso (segments((i - 1)).Y <> segments(i).Y)) Then
                    Return False
                End If
            Next i
            Return True
        End Function

        Private Shared Function GetDesignerEscapeCover(ByVal designer As ActivityDesigner, ByVal escapeLocations As ICollection([Of] Object)) As IList([Of] Point)
            Dim bounds As Rectangle = designer.Bounds
            Dim dictionary As New Dictionary([Of] DesignerEdges, List([Of] Point))
            Dim obj2 As Object
            For Each obj2 In escapeLocations
                Dim none As DesignerEdges = DesignerEdges.None
                Dim empty As Point = Point.Empty
                If TypeOf obj2 Is ConnectionPoint Then
                    none = DirectCast(obj2, ConnectionPoint).ConnectionEdge
                    empty = DirectCast(obj2, ConnectionPoint).Location
                ElseIf TypeOf obj2 Is Point Then
                    empty = DirectCast(obj2, Point)
                    none = DesignerGeometryHelper.ClosestEdgeToPoint(DirectCast(obj2, Point), bounds, DesignerEdges.All)
                End If
                If (none <> DesignerEdges.None) Then
                    Dim list As List([Of] Point) = Nothing
                    If Not dictionary.ContainsKey(none) Then
                        list = New List([Of] Point)
                        dictionary.Add(none, list)
                    Else
                        list = dictionary.Item(none)
                    End If
                    list.Add(empty)
                End If
            Next
            Dim margin As Size = WorkflowTheme.CurrentTheme.AmbientTheme.Margin
            bounds.Inflate(margin)
            Dim dictionary2 As New Dictionary([Of] DesignerEdges, Point())
            Dim pointArray2 As Point() = New Point() { New Point(bounds.Left, bounds.Top), New Point(bounds.Left, bounds.Bottom) }
            dictionary2.Add(DesignerEdges.Left, pointArray2)
            Dim pointArray3 As Point() = New Point() { New Point(bounds.Left, bounds.Top), New Point(bounds.Right, bounds.Top) }
            dictionary2.Add(DesignerEdges.Top, pointArray3)
            Dim pointArray4 As Point() = New Point() { New Point(bounds.Right, bounds.Top), New Point(bounds.Right, bounds.Bottom) }
            dictionary2.Add(DesignerEdges.Right, pointArray4)
            Dim pointArray5 As Point() = New Point() { New Point(bounds.Left, bounds.Bottom), New Point(bounds.Right, bounds.Bottom) }
            dictionary2.Add(DesignerEdges.Bottom, pointArray5)
            Dim list2 As New List([Of] Point)
            Dim edges2 As DesignerEdges
            For Each edges2 In dictionary2.Keys
                If dictionary.ContainsKey(edges2) Then
                    Dim pointArray As Point() = dictionary2.Item(edges2)
                    Dim list3 As List([Of] Point) = dictionary.Item(edges2)
                    Dim list4 As New List([Of] Point)
                    Select Case edges2
                        Case DesignerEdges.Left
                            list4.Add(New Point(pointArray(0).X, pointArray(0).Y))
                            Dim j As Integer
                            For j = 0 To list3.Count - 1
                                Dim point2 As Point = list3.Item(j)
                                If (((point2.X > pointArray(0).X) AndAlso (point2.Y > pointArray(0).Y)) AndAlso (point2.Y < pointArray(1).Y)) Then
                                    list4.Add(New Point(pointArray(0).X, (point2.Y - 1)))
                                    list4.Add(New Point((point2.X + 1), (point2.Y - 1)))
                                    list4.Add(New Point((point2.X + 1), (point2.Y + 1)))
                                    list4.Add(New Point(pointArray(0).X, (point2.Y + 1)))
                                End If
                            Next j
                            list4.Add(New Point(pointArray(0).X, pointArray(1).Y))
                            Exit Select
                        Case DesignerEdges.Right
                            list4.Add(New Point(pointArray(0).X, pointArray(0).Y))
                            Dim k As Integer
                            For k = 0 To list3.Count - 1
                                Dim point3 As Point = list3.Item(k)
                                If (((point3.X < pointArray(0).X) AndAlso (point3.Y > pointArray(0).Y)) AndAlso (point3.Y < pointArray(1).Y)) Then
                                    list4.Add(New Point(pointArray(0).X, (point3.Y - 1)))
                                    list4.Add(New Point((point3.X - 1), (point3.Y - 1)))
                                    list4.Add(New Point((point3.X - 1), (point3.Y + 1)))
                                    list4.Add(New Point(pointArray(0).X, (point3.Y + 1)))
                                End If
                            Next k
                            list4.Add(New Point(pointArray(0).X, pointArray(1).Y))
                            Exit Select
                        Case DesignerEdges.Top
                            list4.Add(New Point(pointArray(0).X, pointArray(0).Y))
                            Dim m As Integer
                            For m = 0 To list3.Count - 1
                                Dim point4 As Point = list3.Item(m)
                                If (((point4.Y > pointArray(0).Y) AndAlso (point4.X > pointArray(0).X)) AndAlso (point4.X < pointArray(1).X)) Then
                                    list4.Add(New Point((point4.X - 1), pointArray(0).Y))
                                    list4.Add(New Point((point4.X - 1), (point4.Y + 1)))
                                    list4.Add(New Point((point4.X + 1), (point4.Y + 1)))
                                    list4.Add(New Point((point4.X + 1), pointArray(0).Y))
                                End If
                            Next m
                            list4.Add(New Point(pointArray(1).X, pointArray(0).Y))
                            Exit Select
                        Case DesignerEdges.Bottom
                            list4.Add(New Point(pointArray(0).X, pointArray(0).Y))
                            Dim n As Integer
                            For n = 0 To list3.Count - 1
                                Dim point5 As Point = list3.Item(n)
                                If (((point5.Y < pointArray(0).Y) AndAlso (point5.X > pointArray(0).X)) AndAlso (point5.X < pointArray(1).X)) Then
                                    list4.Add(New Point((point5.X - 1), pointArray(0).Y))
                                    list4.Add(New Point((point5.X - 1), (point5.Y - 1)))
                                    list4.Add(New Point((point5.X + 1), (point5.Y - 1)))
                                    list4.Add(New Point((point5.X + 1), pointArray(0).Y))
                                End If
                            Next n
                            list4.Add(New Point(pointArray(1).X, pointArray(0).Y))
                            Exit Select
                    End Select
                    Dim i As Integer
                    For i = 1 To list4.Count - 1
                        list2.Add(list4.Item((i - 1)))
                        list2.Add(list4.Item(i))
                    Next i
                    [Continue] For
                End If
                list2.AddRange(dictionary2.Item(edges2))
            Next
            Return list2.AsReadOnly
        End Function

        Public Shared Sub GetRoutingObstacles(ByVal serviceProvider As IServiceProvider, ByVal source As Object, ByVal target As Object, <Out> ByRef rectanglesToExclude As List([Of] Rectangle), <Out> ByRef linesToExclude As List([Of] Point), <Out> ByRef pointsToExclude As List([Of] Point))
            Dim ambientTheme As AmbientTheme = WorkflowTheme.CurrentTheme.AmbientTheme
            Dim safeRootDesigner As ActivityDesigner = ActivityDesigner.GetSafeRootDesigner(serviceProvider)
            Dim point As ConnectionPoint = [TryCast](source,ConnectionPoint)
            Dim point2 As Point = If((Not point Is Nothing), point.Location, DirectCast(source, Point))
            Dim designer As ActivityDesigner = If((Not point Is Nothing), point.AssociatedDesigner, safeRootDesigner.HitTest(point2).AssociatedDesigner)
            Dim point3 As ConnectionPoint = [TryCast](target,ConnectionPoint)
            Dim point4 As Point = If((Not point3 Is Nothing), point3.Location, DirectCast(target, Point))
            Dim designer3 As ActivityDesigner = If((Not point3 Is Nothing), point3.AssociatedDesigner, safeRootDesigner.HitTest(point4).AssociatedDesigner)
            Dim dictionary As New Dictionary([Of] Integer, ActivityDesigner)
            If (Not designer Is Nothing) Then
                Dim designer4 As CompositeActivityDesigner = designer.ParentDesigner
                Do While (Not designer4 Is Nothing)
                    If dictionary.ContainsKey(designer4.GetHashCode) Then
                        Exit Do
                    End If
                    dictionary.Add(designer4.GetHashCode, designer4)
                    designer4 = designer4.ParentDesigner
                Loop
            End If
            If (Not designer3 Is Nothing) Then
                Dim designer5 As CompositeActivityDesigner = designer3.ParentDesigner
                Do While (Not designer5 Is Nothing)
                    If dictionary.ContainsKey(designer5.GetHashCode) Then
                        Exit Do
                    End If
                    dictionary.Add(designer5.GetHashCode, designer5)
                    designer5 = designer5.ParentDesigner
                Loop
            End If
            rectanglesToExclude = New List([Of] Rectangle)
            pointsToExclude = New List([Of] Point)
            Dim designer6 As CompositeActivityDesigner
            For Each designer6 In dictionary.Values
                Dim containedDesigners As ReadOnlyCollection([Of] ActivityDesigner) = designer6.ContainedDesigners
                Dim i As Integer
                For i = 0 To containedDesigners.Count - 1
                    Dim designer7 As ActivityDesigner = containedDesigners.Item(i)
                    If ((designer7.IsVisible AndAlso Not dictionary.ContainsKey(designer7.GetHashCode)) AndAlso ((Not designer7 Is designer) AndAlso (Not designer7 Is designer3))) Then
                        Dim bounds As Rectangle = designer7.Bounds
                        bounds.Inflate(ambientTheme.Margin)
                        rectanglesToExclude.Add(bounds)
                    End If
                Next i
            Next
            linesToExclude = New List([Of] Point)
            If (((Not designer Is Nothing) AndAlso (designer Is designer3)) AndAlso Not designer.IsRootDesigner) Then
                linesToExclude.AddRange(ActivityDesignerConnectorRouter.GetDesignerEscapeCover(designer, New Object() { source, target }))
            Else
                If ((Not designer Is Nothing) AndAlso Not designer.IsRootDesigner) Then
                    linesToExclude.AddRange(ActivityDesignerConnectorRouter.GetDesignerEscapeCover(designer, New Object() { source }))
                End If
                If ((Not designer3 Is Nothing) AndAlso Not designer3.IsRootDesigner) Then
                    Dim flag As Boolean = True
                    Dim designer8 As CompositeActivityDesigner = If((Not designer Is Nothing), designer.ParentDesigner, Nothing)
                    Do While (Not designer8 Is Nothing)
                        If (designer3 Is designer8) Then
                            flag = False
                            Exit Do
                        End If
                        designer8 = If((Not designer Is Nothing), designer8.ParentDesigner, Nothing)
                    Loop
                    If flag Then
                        linesToExclude.AddRange(ActivityDesignerConnectorRouter.GetDesignerEscapeCover(designer3, New Object() { target }))
                    End If
                End If
            End If
        End Sub

        Public Shared Function Route(ByVal serviceProvider As IServiceProvider, ByVal source As Object, ByVal target As Object, ByVal userDefinedRoutingObstacles As ICollection([Of] Rectangle)) As Point()
            Dim list As List([Of] Rectangle)
            Dim list2 As List([Of] Point)
            Dim list3 As List([Of] Point)
            ActivityDesignerConnectorRouter.GetRoutingObstacles(serviceProvider, source, target, list, list2, list3)
            If (Not userDefinedRoutingObstacles Is Nothing) Then
                list.AddRange(userDefinedRoutingObstacles)
            End If
            Dim safeRootDesigner As ActivityDesigner = ActivityDesigner.GetSafeRootDesigner(serviceProvider)
            Dim ambientTheme As AmbientTheme = WorkflowTheme.CurrentTheme.AmbientTheme
            Dim begin As Point = If(TypeOf source Is ConnectionPoint, DirectCast(source, ConnectionPoint).Location, DirectCast(source, Point))
            Dim end As Point = If(TypeOf target Is ConnectionPoint, DirectCast(target, ConnectionPoint).Location, DirectCast(target, Point))
            Dim segments As Point() = ConnectorRouter.Route(begin, [end], New Size((2 * ambientTheme.Margin.Width), (2 * ambientTheme.Margin.Height)), safeRootDesigner.Bounds, list.ToArray, list2.ToArray, list3.ToArray)
            If Not ActivityDesignerConnectorRouter.AreAllSegmentsVerticalOrHorizontal(segments) Then
                segments = ConnectorRouter.Route(begin, [end], ambientTheme.Margin, safeRootDesigner.Bounds, New Rectangle(0  - 1) {}, list2.ToArray, New Point(0  - 1) {})
            End If
            If Not ActivityDesignerConnectorRouter.AreAllSegmentsVerticalOrHorizontal(segments) Then
                Dim point3 As Point = If((DesignerGeometryHelper.SlopeOfLineSegment(begin, [end]) < 1!), New Point([end].X, begin.Y), New Point(begin.X, [end].Y))
                segments = New Point() { begin, point3, [end] }
            End If
            Return segments
        End Function

    End Class
End Namespace

